/*
 * FreeModbus Libary: BARE Demo Application
 * Copyright (C) 2006 Christian Walter <wolti@sil.at>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id: demo.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
 */

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb_cb.h"
#include "global.h"
/* ----------------------- Defines ------------------------------------------*/

/* ----------------------- Static variables ---------------------------------*/
static sModbus lgsModbus_inst;
/* ----------------------- Defines ------------------------------------------*/

/* ----------------------- Static variables ---------------------------------*/

// mb_reg_st lgsModbus_inst;

eMBErrorCode eMBRegInputCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNRegs)
{
    return MB_ENOREG;
}

/*********************************************************
  * @name   eMBRegHoldingCB
    * @brief  modbus holding register operation call back function
    * @calls  None
  * @called modbus protocal stack
  * @param  None
  * @retval The return value can be:
                        @arg MB_ENOERR:
            @arg MB_ENORES:
*********************************************************/
eMBErrorCode eMBRegHoldingCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode)
{
    //    extern g_var_st g_var_st_inst;

    eMBErrorCode eStatus = MB_ENOERR;
    int iRegIndex;

    if (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NUM)
    {
        iRegIndex = (int)(usAddress - lgsModbus_inst.u8RegStart);
        switch (eMode)
        {
            // Pass current register values to the protocol stack.
            case MB_REG_READ:
                while (usNRegs > 0)
                {
                    *pucRegBuffer++ = (UCHAR)(lgsModbus_inst.u16RegBuffer[iRegIndex] >> 8);
                    *pucRegBuffer++ = (UCHAR)(lgsModbus_inst.u16RegBuffer[iRegIndex] & 0xFF);
                    iRegIndex++;
                    usNRegs--;
                }
                break;

            // Update current register values with new values from the protocol stack.
            case MB_REG_WRITE:
                while (usNRegs > 0)
                {
                    if (lgsModbus_inst.u8RegProperty[iRegIndex] == 0)  // if reg is RO, quit process
                    {
                        eStatus = MB_EIO;
                        break;
                    }
                    lgsModbus_inst.u16RegBuffer[iRegIndex] = *pucRegBuffer++ << 8;
                    lgsModbus_inst.u16RegBuffer[iRegIndex] |= *pucRegBuffer++;
                    lgsModbus_inst.u8RegStatus[iRegIndex] = 1;  // content change measn new cmd request

                    iRegIndex++;
                    usNRegs--;
                }
                break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

eMBErrorCode eMBRegCoilsCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode)
{
    return MB_ENOREG;
}

eMBErrorCode eMBRegDiscreteCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNDiscrete)
{
    return MB_ENOREG;
}

/*********************************************************
 * @name   SetWorkMode
 * @brief  switch to factory mode, in which all modbus regs could be accessed
 * @calls  ConfigRegister()
 * @called None
 * @param  None
 * @retval None
 *********************************************************/
static void SetWorkMode(uint8_t WorkMode)
{
    uint16_t i;

    if (WorkMode)  //用户模式
    {
        lgsModbus_inst.u16RegBuffer[18] &= ~0x0001;  // reset status flag bit that indcates factory mode
        for (i = 0; i < REG_HOLDING_NUM; i++)
        {
            lgsModbus_inst.u8RegProperty[i] = 0;
        }
        lgsModbus_inst.u8RegProperty[19] = 1;  // active device seting change permission
    }
    else  //工厂模式
    {
        lgsModbus_inst.u16RegBuffer[18] |= 0x0001;  // set status flag bit that indcates factory mode
        for (i = 0; i < REG_HOLDING_NUM; i++)
        {
            lgsModbus_inst.u8RegProperty[i] = 1;
        }
    }
}

/*********************************************************
  * @name   MBREGDeflaut
    * @brief  reset to initial factory parameters
    * @calls  ResetDefaultParameter();

  * @called SetWorkMode(1);//用户模式();
  * @param  None
  * @retval None
*********************************************************/
static void MBREGDeflaut(void)
{
    uint16_t i;

    lgsModbus_inst.u8RegStart = REG_HOLDING_START;
    //		if(g_sVariable.u8SA)
    //		{
    //				lgsModbus_inst.u16RegBuffer[0] = REG_HOLDING_NUM;
    //		}
    //		else
    //		{
    //				lgsModbus_inst.u16RegBuffer[0] = REG_HOLDING_NUM;
    //		}
    lgsModbus_inst.u16RegBuffer[0]  = REG_HOLDING_NUM;
    lgsModbus_inst.u16RegBuffer[1]  = (uint16_t)((MB_DEVICE_TYPE[0] << 8) | MB_DEVICE_TYPE[1]);
    lgsModbus_inst.u16RegBuffer[2]  = (uint16_t)((MB_DEVICE_TYPE[2] << 8) | MB_DEVICE_TYPE[3]);
    lgsModbus_inst.u16RegBuffer[3]  = (uint16_t)((MB_SOFTWARE_VER << 8) | MB_SOFTWARE_SUBVER);
    lgsModbus_inst.u16RegBuffer[4]  = (uint16_t)((MB_HARDWARE_VER << 8) | MB_HARDWARE_SUBVER);
    lgsModbus_inst.u16RegBuffer[5]  = (uint16_t)((MB_SERIAL_NO[0] << 8) | MB_SERIAL_NO[1]);
    lgsModbus_inst.u16RegBuffer[6]  = (uint16_t)((MB_SERIAL_NO[2] << 8) | MB_SERIAL_NO[3]);
    lgsModbus_inst.u16RegBuffer[7]  = (uint16_t)((MB_SERIAL_NO[4] << 8) | MB_SERIAL_NO[5]);
    lgsModbus_inst.u16RegBuffer[8]  = (uint16_t)((MB_SERIAL_NO[6] << 8) | MB_SERIAL_NO[7]);
    lgsModbus_inst.u16RegBuffer[9]  = (uint16_t)((MB_MAN_DATE[0] << 8) | MB_MAN_DATE[1]);
    lgsModbus_inst.u16RegBuffer[10] = (uint16_t)((MB_MAN_DATE[0] << 8) | MB_MAN_DATE[1]);
    if (g_sVariable.u8SA)
    {
        //				lgsModbus_inst.u16RegBuffer[11] =GetCommAddress();
        lgsModbus_inst.u16RegBuffer[11] = MB_DEVICE_SA_ADDR;
    }
    else
    {
        lgsModbus_inst.u16RegBuffer[11] = MB_DEVICE_SP_ADDR;
    }
    lgsModbus_inst.u16RegBuffer[12] = MB_BAUDRATE;
    for (i = 13; i < 20; i++)
    {
        lgsModbus_inst.u16RegBuffer[i] = 0;
    }
    SetWorkMode(1);  //用户模式()
}

/*********************************************************
  * @name   cmd_mb_stack_restart
    * @brief  restart modbus protocal stack, update device address or/and communication baudrate
    * @calls  MBGetAddrsee(),
            MBGetBaudrate(),
            eMBDisable(),
            eMBInit();
                        eMBEnable();
  * @called ();
  * @param  None
  * @retval None
*********************************************************/
static eMBErrorCode MBStackRestart(void)
{
    eMBErrorCode eStatus = MB_ENOERR;

    osDelay(50);
    eStatus = eMBDisable();
    if (eStatus != MB_ENOERR)
    {
        return eStatus;
    }
    eStatus = eMBInit(MB_RTU, MBGetAddrsee(), USART0_CH, MBGetBaudrate(), MB_PAR_NONE);
    if (eStatus != MB_ENOERR)
    {
        return eStatus;
    }
    eStatus = eMBEnable();
    return eStatus;
}

/*********************************************************
 * @name   SaveSettings
 * @brief  save current modbus register data into flashrom
 * @calls  ()
 * @called flash_write()
 * @param  None
 * @retval None
 *********************************************************/
void SaveSettings(void)
{
    lgsModbus_inst.u8PgFlag = MB_FLASH_WR_FLAG;
    Flash_Write(FLASH_USER_START, (uint16_t *)&lgsModbus_inst, (sizeof(sModbus) / 2));
}

/*********************************************************
  * @name   ResetDefaultParameter
    * @brief  reset system parameters to default values
    * @calls  ConfigRegister()
  * @called MBREGDeflaut(),
                        eMBClose(),
            eMBDisable(),
            eMBInit(),
                        eMBEnable();
  * @param  None
  * @retval None
*********************************************************/
static eMBErrorCode ResetDefaultParameter(void)
{
    eMBErrorCode eStatus = MB_ENOERR;

    osDelay(50);
    eStatus = eMBDisable();
    if (eStatus != MB_ENOERR)
    {
        return eStatus;
    }
    eStatus = eMBClose();
    if (eStatus != MB_ENOERR)
    {
        return eStatus;
    }
    MBREGDeflaut();
    eStatus = eMBInit(MB_RTU, MBGetAddrsee(), USART0_CH, MBGetBaudrate(), MB_PAR_NONE);
    if (eStatus != MB_ENOERR)
    {
        return eStatus;
    }
    eStatus = eMBEnable();
    return eStatus;
}

/*********************************************************
  * @name   SystemReset
    * @brief  system software reset
    * @calls  ConfigRegister()
  * @called eMBDisable(),
                        eMBClose(),
                        NVIC_SystemReset();
  * @param  None
  * @retval None
*********************************************************/
// static void SystemReset(void)
void SystemReset(void)
{
    osDelay(100);
    eMBDisable();
    eMBClose();
    NVIC_SystemReset();
}

/*********************************************************
  * @name   ConfigRegister
    * @brief  modbus configuration register command execution
    * @calls
  * @called ResetDefaultParameter(),
                        SystemReset(),
                        SetWorkMode;
  * @param  None
  * @retval None
*********************************************************/
static void ConfigRegister(uint16_t u16CMD)
{
    switch (u16CMD)
    {
        case (CMD_MB_SAVE_FLASH): {
            SaveSettings();  //保存设置
            break;
        }
        case (CMD_MB_SYS_RESET): {
            SystemReset();  //系统复位
            break;
        }
        case (CMD_MB_RESET_DEFAULT): {
            ResetDefaultParameter();  //复位默认参数
            Delay(50);
            SaveSettings();
            break;
        }
        case (CMD_MB_USER_MODE): {
            SetWorkMode(1);  //用户模式
            break;
        }
        case (CMD_MB_FACTORY_MODE): {
            SetWorkMode(0);  //工厂模式
            break;
        }
        default: {
            break;
        }
    }
}

/*********************************************************
  * @name   MBGetBaudrate
    * @brief  get current modbus communication baudrate
    * @calls  MBStackRestart(),
                        ResetDefaultParameter(),
  * @called None
  * @param  None
  * @retval baudrate
*********************************************************/
uint16_t MBGetBaudrate(void)
{
    return lgsModbus_inst.u16RegBuffer[12];
}

/*********************************************************
  * @name   MBGetAddrsee
    * @brief  get current modbus communication address
    * @calls  MBStackRestart(),
                        ResetDefaultParameter(),
  * @called None
  * @param  None
  * @retval device modbus slave address
*********************************************************/
uint8_t MBGetAddrsee(void)
{
    return lgsModbus_inst.u16RegBuffer[11];
}

/*********************************************************
  * @name   MBRegsiterUpdate
    * @brief  update modbus user registers according to internal status and data aquired
    * @calls
                        com_proc(),
  * @called None
  * @param  None
  * @retval None
*********************************************************/
INT8U MBRegsiterUpdate(INT8U u8Byte)
{
    //#ifdef  	SA
    //		memcpy((u8*)&lgsModbus_inst.u16RegBuffer[20],(u8*)g_sVariable.sTemperatureHumidity_inst.u16Temperature.acBytes,2*2);
    ////读温湿度数据 #else
    //		memcpy((u8*)&lgsModbus_inst.u16RegBuffer[20],(u8*)g_sVariable.sPower_inst.u16Voltage,sizeof(sPower));
    ////读电源测量数据 #endif
    if (g_sVariable.u8SA)
    {
        if (u8Byte)
        {
            g_sVariable.u8UpdateAddr++;
            if (g_sVariable.u8UpdateAddr > 30)
            {
                static uint16_t addr            = 0;
                g_sVariable.u8UpdateAddr        = 0x00;
                lgsModbus_inst.u16RegBuffer[11] = GetCommAddress();
                if (addr != lgsModbus_inst.u16RegBuffer[11])
                {
                    MBStackRestart();
                    addr = lgsModbus_inst.u16RegBuffer[11];
                }
            }
            //						lgsModbus_inst.u16RegBuffer[11] = g_sVariable.u8Addr;
        }
        memcpy((u8 *)&lgsModbus_inst.u16RegBuffer[20], (u8 *)&g_sVariable.sTemperatureHumidity_inst.u16State,
               sizeof(sTemperatureHumidity));  //读温湿度数据
    }
    else
    {
        //				g_sVariable.sPower_inst.u16State=g_sVariable.sPower_inst.u16PhaseSequence;//赋值给状态位
        g_sVariable.sPower_inst.u16PhaseSequence = g_sVariable.sPower_inst.PTest.lValue % 0xFFFF;  //赋值给状态位
        memcpy((u8 *)&lgsModbus_inst.u16RegBuffer[20], (u8 *)&g_sVariable.sPower_inst.u16State, 20);  //读电源测量数据

        __nop();
        __nop();
    }
    return TRUE;
}

/*********************************************************
  * @name   MBRegsiterInit
    * @brief  modbus registers initialization, load data from flashrom if is programed, otherwise, set modbus registers
with default value
    * @calls  MBREGDeflaut(),
                        com_proc(),
  * @called MBRegsiterUpdate(0);//MB数据更新
  * @param  None
  * @retval None
*********************************************************/
INT8U MBRegsiterInit(void)
{
    // sModbus *MBREGPtr = (sModbus *)(FLASH_USER_START);
    // if (MBREGPtr->u8PgFlag != MB_FLASH_WR_FLAG)
    {
        MBREGDeflaut();  // load default
    }
    // else
    // {
    //     memcpy(&lgsModbus_inst, (const void *)FLASH_USER_START, sizeof(sModbus));  // load reg from flash
    // }

    MBRegsiterUpdate(0);  // MB数据更新
    return TRUE;
}
/*********************************************************
  * @name   MBResolve
    * @brief  scan writable modbus registers, if modified, call according handler
    * @calls  com_proc();
  * @called MBStackRestart(),
                        ConfigRegister(),
                        SaveSettings();
  * @param  None
  * @retval None
*********************************************************/
void MBResolve(void)
{
    INT8U u8Register;
    uint16_t i;

    for (i = 0; i < REG_HOLDING_NUM; i++)
    {
        if (lgsModbus_inst.u8RegStatus[i] != MB_REG_READ)
        {
            switch (i)
            {
                case (11):  // address change//通信地址
                {
                    if ((lgsModbus_inst.u16RegBuffer[i] < 1) || (lgsModbus_inst.u16RegBuffer[i] > 247))
                    {
                        lgsModbus_inst.u16RegBuffer[i] = 0x01;
                    }
                    MBStackRestart();
                    break;
                }
                case (12):  // baudrate change//通信速率
                {
                    if ((lgsModbus_inst.u16RegBuffer[i] != 9600) && (lgsModbus_inst.u16RegBuffer[i] != 4800) &&
                        (lgsModbus_inst.u16RegBuffer[i] != 2400) && (lgsModbus_inst.u16RegBuffer[i] != 1200))
                    {
                        lgsModbus_inst.u16RegBuffer[i] = 4800;
                    }
                    MBStackRestart();
                    break;
                }
                case (19):  //修改配置寄存器
                {
                    ConfigRegister(lgsModbus_inst.u16RegBuffer[i]);
                    lgsModbus_inst.u16RegBuffer[i] = 0;
                    break;
                }
                case (29):  //校表初始化
                    if (lgsModbus_inst.u16RegBuffer[i] != 0x5A)
                    {
                        return;
                    }
                    else
                    {
                        CalibrateClean();  //??????
                    }
                case (30):  //校表A相
                    u8Register = PHASE_A_GAIN;
                case (31):  //校表B相
                    u8Register = PHASE_A_GAIN + 1;
                case (32):  //校表C相
                    u8Register = PHASE_A_GAIN + 2;
                    if (CalibrateWrite(u8Register, lgsModbus_inst.u16RegBuffer[i]))  //??
                    {
                        return;
                    }
                    break;
                default: {
                    break;
                }
            }
        }
        lgsModbus_inst.u8RegStatus[i] = MB_REG_READ;
    }
}

// eMBErrorCode
// eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
//{
//    return MB_ENOREG;
//}

// eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
//{
////    extern g_var_st g_var_st_inst;
//
//		eMBErrorCode    eStatus = MB_ENOERR;
//    int             iRegIndex;

//    if( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NUM )
//    {
//
//        iRegIndex = ( int )( usAddress - g_sVariable.sModbus_inst.u8RegStart );
//        switch ( eMode )
//        {
//        // Pass current register values to the protocol stack.
//        case MB_REG_READ:
//            while( usNRegs > 0 )
//            {
//                *pucRegBuffer++ = ( UCHAR ) ( g_sVariable.sModbus_inst.u16RegBuffer[iRegIndex] >> 8 );
//                *pucRegBuffer++ = ( UCHAR ) ( g_sVariable.sModbus_inst.u16RegBuffer[iRegIndex] & 0xFF );
//                iRegIndex++;
//                usNRegs--;
//            }
//            break;

//        // Update current register values with new values from the protocol stack.
//        case MB_REG_WRITE:
//            while( usNRegs > 0 )
//            {
//								if(g_sVariable.sModbus_inst.u8RegProperty[iRegIndex] == 0)					//if reg is
// RO, quit process
//								{
//										eStatus = MB_EIO;
//										break;
//								}
//								g_sVariable.sModbus_inst.u16RegBuffer[iRegIndex] = *pucRegBuffer++ << 8;
//                g_sVariable.sModbus_inst.u16RegBuffer[iRegIndex] |= *pucRegBuffer++;
//								g_sVariable.sModbus_inst.u8RegStatus[iRegIndex] = MB_REG_WRITE;
////content change measn new cmd request

//                iRegIndex++;
//                usNRegs--;
//            }
//            break;
//        }
//    }
//    else
//    {
//        eStatus = MB_ENOREG;
//    }
//    return eStatus;
//}

// eMBErrorCode
// eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
//               eMBRegisterMode eMode )
//{
//    return MB_ENOREG;
//}

// eMBErrorCode
// eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
//{
//    return MB_ENOREG;
//}
